import { AcGameObject } from "./AcGameObject";
import { Cell } from "./Cell";

export class Snake extends AcGameObject {
  constructor(ctx, gamemap) {
    super()
    this.ctx = ctx
    this.gamemap = gamemap
    this.cells = []
    this.color = '#4876EC'
    // 方向：上右下左，分别用下标0、1、2、3表示
    this.dirs = [
      { x: 0, y: -1 },
      { x: 1, y: 0 },
      { x: 0, y: 1 },
      { x: -1, y: 0 }
    ]
    // 初始方向：右【蛇头方向】
    this.direction = 1
    // 偏移值
    this.eps = 1e-1
    // this.eps = 1e-2
    // 表示每秒钟走几个格子，可间接调节速度
    this.speed = 4

    // 随机生成苹果
    this.apple_cell = new Cell(-1, -1)
    this.apple_img = new Image()
    this.apple_img.src = require('@/assets/imgs/apple.svg')
    this.eating = false
    this.tail_cell = null
  }

  put_an_apple() {
    const positions = new Set()
    for(let i = 0; i < 17; i++) {
      for(let j = 0; j < 15; j++) {
        positions.add(`${i}-${j}`)
      }
    }
    for(let cell of this.cells) {
      positions.delete(`${cell.i}-${cell.j}`)
    }
    const items = Array.from(positions)
    if(items.length === 0) {
      this.gamemap.win()
    } else {
      let [x, y] = items[Math.floor(Math.random() * items.length)].split('-')
      x = parseInt(x)
      y = parseInt(y)
      this.apple_cell = new Cell(x, y)
    }
  }

  start() {
    this.cells.push(new Cell(8, 7))
    for(let i = 8; i > 0; i--) {
      this.cells.push(new Cell(i, 7))
    }

    this.put_an_apple()
  }
  update() {
    if(this.gamemap.status === 'playing') {
      this.update_body()
    }

    this.render() // 必须得放后面，因为要根据状态变颜色
  }
  check_die() {
    const head = this.cells[0]

    // 撞墙
    // 注意： head.i >= 17 与 head.j >= 15 是可以等于的，因为如果靠墙出现的苹果得能及时转弯吃掉，否则根本吃不掉
    if(head.i < 0 || head.i >= 17 || head.j < 0 || head.j >= 15) {
      log('撞墙了！')
      return true
    }

    // 撞自己
    for(let i = 2; i < this.cells.length; i++) {
      if(this.cells[i].i === head.i && this.cells[i].j === head.j) {
        console.log('撞到自己了！')
        return true
      }
    }
      
    return false
  }
  update_body() {
    const k = this.cells.length - 1
    // 计算从左往右的第一个球走到第二个球的方向。【蛇尾方向】
    const d = this.get_direction(this.cells[k], this.cells[k - 1] )

    if(d >= 0) {
      // timeDelta单位是毫秒
      const distance = this.speed * this.timeDelta / 1000
      // 右侧第一个【蛇头】;方向：this.dirs[d].x
      this.cells[0].x += this.dirs[this.direction].x * distance
      this.cells[0].y += this.dirs[this.direction].y * distance
      // 左侧第一个【蛇尾】;方向：this.dirs[d].y 
      this.cells[k].x += this.dirs[d].x * distance
      this.cells[k].y += this.dirs[d].y * distance
    } else {

      // 刷新蛇身
      const _cells = []
      // 新蛇头：this.cells[1]
      const headi = this.cells[1].i + this.dirs[this.direction].x
      const headj = this.cells[1].j + this.dirs[this.direction].y
      _cells.push(new Cell(headi, headj))
      _cells.push(new Cell(headi, headj))
      for(let i = 1; i < k; i++) {
        _cells.push(this.cells[i])
      }
      this.cells = _cells

      if(this.eating) {
        this.cells.push(this.tail_cell)
        this.eating = false
      }

      // this.direction ^ 2 位运算取反，得到反方向
      // 这里判断缓存的下一个要执行的方向是否合理，不合理则删除
      // ^ 的优先级可能小于 ===，所以必须加括号
      const ds = this.gamemap.directions
      while(ds.length > 0 && (ds[0] === this.direction || ds[0] === (this.direction ^ 2))) {
        ds.splice(0, 1)
        // ds.shift()
      }
      if(ds.length > 0) {
        this.direction = ds[0]
        ds.splice(0, 1)
        // this.direction = ds.shift()
      }


      // 优化：this.gamemap.status !== 'lose'，减少不必要的执行
      // if(this.check_die()) {
      //   this.gamemap.lose()
      //   console.log('check_die---lose')
      // }

      // 检查是否死亡
      // 优化：this.gamemap.status !== 'lose'，减少不必要的执行
      if(this.gamemap.status !== 'lose' && this.check_die()) {
        this.gamemap.lose()
      }

      // 蛇撞到苹果
      if(headi == this.apple_cell.i && headj === this.apple_cell.j) {
        this.eating = true
        // 将蛇尾的那个圆的位置保存下来。
        // 注意：这里必须new，不能复用，因为保存时引用，会变
        const cell = this.cells[this.cells.length - 1]
        this.tail_cell = new Cell(cell.i, cell.j)
        this.put_an_apple()

        // 记录分数
        const score = this.gamemap.store.state.score + 1
        this.gamemap.store.commit('updateScore', score)
        this.gamemap.store.commit('updateRecord', score)
      }

    }
  }
  get_direction(a, b) {
    // 小于该偏移值认为重合
    if(Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps) {
      return -1
    }
    if(Math.abs(a.x - b.x) < this.eps) {
      if(b.y < a.y) return 0
      else return 2
    }
    if(b.x > a.x) return 1
    return 3
  }

  // 绘制图形
  /**
   * 1.注意“优化吃到苹果时的动画”那里是可以不要的，加了的话更流畅
   */
  render() {
    const L = this.gamemap.L
    // console.log('color', this.color)

    // 优化吃到苹果时的动画
    if(this.eating) {
      this.cells.push(this.tail_cell)
    }

    // // 画圆形
    // this.ctx.fillStyle = this.color
    // for(let cell of this.cells) {
    //   this.ctx.beginPath()
    //   this.ctx.arc(cell.x * L, cell.y * L, L / 2, 0, 2 * Math.PI)
    //   this.ctx.fill()
    // }

    // // 画矩形【非核心代码，可省略，此处优化蛇的外观】
    // // 从左往右的第二个开始，每个圆形都与前一个圆形之间画矩形
    // for(let i = 1; i < this.cells.length; i++) {
    //   const a = this.cells[i - 1], b = this.cells[i]
    //   if(Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps) {
    //     // 这里认为没有偏移
    //     continue
    //   }
    //   if(Math.abs(a.x - b.x) < this.eps) {
    //     // 上下方向移动时
    //     // Math.min(a.y, b.y)这里是综合方向为上下的两种情况
    //     this.ctx.fillRect((a.x - 0.5) * L, Math.min(a.y, b.y) * L, L, Math.abs(a.y - b.y) * L);
    //   } else {
    //     // 左右方向移动时
    //     this.ctx.fillRect(Math.min(a.x, b.x) * L, (a.y - 0.5) * L, Math.abs(a.x - b.x) * L,  L);
    //   }
    // }

    // 优化：给蛇瘦身
    // 画圆形
    this.ctx.fillStyle = this.color
    for(let cell of this.cells) {
      this.ctx.beginPath()
      this.ctx.arc(cell.x * L, cell.y * L, L / 2 * 0.8, 0, 2 * Math.PI)
      this.ctx.fill()
    }
    // 画矩形【非核心代码，可省略，此处优化蛇的外观】
    // 从左往右的第二个开始，每个圆形都与前一个圆形之间画矩形
    for(let i = 1; i < this.cells.length; i++) {
      const a = this.cells[i - 1], b = this.cells[i]
      if(Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps) {
        // 这里认为没有偏移
        continue
      }
      if(Math.abs(a.x - b.x) < this.eps) {
        // 上下方向移动时
        // Math.min(a.y, b.y)这里是综合方向为上下的两种情况
        this.ctx.fillRect((a.x - 0.5 + 0.1) * L, Math.min(a.y, b.y) * L, L * 0.8, Math.abs(a.y - b.y) * L);
      } else {
        // 左右方向移动时
        this.ctx.fillRect(Math.min(a.x, b.x) * L, (a.y - 0.5 + 0.1) * L, Math.abs(a.x - b.x) * L,  L * 0.8);
      }
    }

    // 画苹果
    this.ctx.drawImage(this.apple_img, this.apple_cell.i * L, this.apple_cell.j * L, L, L);
      
    // 优化吃到苹果时的动画
    if(this.eating) {
      this.cells.pop()
    }
  }
}